package com.ch09.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.github.pagehelper.PageInterceptor;
import org.apache.ibatis.logging.stdout.StdOutImpl;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

/**
 * @ClassName MybatisConfig
 * @Description TODO
 * @Author Kx
 * @Date 2025/5/18 18:39
 * @Version 1.0
 */
// 标识为配置类
@Configuration
// 扫描指定包下的所有Mapper接口
@MapperScan("com.ch09.mapper")
// 开启事务管理
@EnableTransactionManagement
public class MybatisConfig {
    /**
     * @author: kx
     * @date: 2025/5/18 18:58
     * @return com.alibaba.druid.pool.DruidDataSource
     * @description: 配置Druid数据源连接池
    */
    @Bean(initMethod = "init", destroyMethod = "close")
    // @Bean: 注解用于创建对象，并交给Spring容器管理
    // initMethod: 初始化完成后的调用方法,用于执行初始化操作
    // destroyMethod: 销毁前调用的方法,用于执行销毁操作
    public DruidDataSource dataSource() {
        // 读取配置文件
        try (InputStream resourceAsStream = MybatisConfig.class.getClassLoader().getResourceAsStream("jdbc.properties")) {
            // 创建数据源
            Properties properties = new Properties();

            // 加载配置文件
            properties.load(resourceAsStream);

            // 返回数据源
            return (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            throw new RuntimeException("加载配置文件失败", e);
        }
    }

    /**
     * @author: kx
     * @date: 2025/5/18 19:20
     * @return org.mybatis.spring.SqlSessionFactoryBean
     * @description: 装配MyBatis的配置信息,存入到Spring容器中管理
    */
    @Bean()
    public SqlSessionFactoryBean sqlSessionFactory() throws IOException {
        // 创建SqlSessionFactoryBean,用于配置MyBatis的配置信息
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();

        // 注入数据源
        sqlSessionFactoryBean.setDataSource(dataSource());

        // 设置实体的别名
        sqlSessionFactoryBean.setTypeAliasesPackage("com.ch09.entity");

        // 创建资源路径匹配解析器对象
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();

        // 设置mapper映射配置文件路径
        sqlSessionFactoryBean.setMapperLocations(resolver.getResources("classpath:mappers/*.xml"));

        // 配置分页插件
        // 创建分页插件对象
        PageInterceptor pageInterceptor = new PageInterceptor();
        // 设置分页属性
        // 创建属性对象
        Properties properties = new Properties();
        // 指定分页插件为MySQL
        properties.setProperty("helperDialect", "mysql");
        // 设置是否支持方法参数
        properties.setProperty("supportMethodsArguments", "true");
        // 设置是否支持分页
        properties.setProperty("reasonable", "true");
        // 把属性对象设置给分页插件对象
        pageInterceptor.setProperties(properties);

        // 将分页插件对象添加到SqlSessionFactoryBean对象中
        sqlSessionFactoryBean.setPlugins(pageInterceptor);

        // 启用sql日志
        // 创建configuration对象,用于手动配置MyBatis
        org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
        // 设置使用的日志实现类为StdOutImpl
        configuration.setLogImpl(StdOutImpl.class);

        // 将configuration对象设置到SqlSessionFactoryBean对象中
        sqlSessionFactoryBean.setConfiguration(configuration);

        return sqlSessionFactoryBean;
    }

    /**
     * @author: kx
     * @date: 2025/5/18 19:22
     * @param dataSource : 数据源
     * @return org.springframework.transaction.PlatformTransactionManager
     * @description: 装配事务管理器
    */
    public PlatformTransactionManager annotationDrivenTransactionManager(DataSource dataSource) {
        // 返回事务管理器对象
        return new DataSourceTransactionManager(dataSource);
    }
}
